﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace lumo.input
{
    /// <summary>
    /// A simple thumbstick using 2 Axes
    /// </summary>
    public class Thumbstick : IThumbstick
    {
        /// <summary>
        /// The XAxis
        /// </summary>
        public IAxis XAxis;

        /// <summary>
        /// The YAxis
        /// </summary>
        public IAxis YAxis;

        // Private variables
        private bool LastDown;
        private bool CurrentDown;
        private float RepeatCount = 0;
        private float _RepeatDelay = Config.DefaultRepeatDelay;
        private float _RepeatTime = Config.DefaultRepeatTime;
        private Vector2 _Vector;

        // The propertie for frame ID
        private uint _FrameID = 0;
        /// <summary>Access for FrameID</summary>
        public uint FrameID { get { return _FrameID; } }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="XAxis">The XAxis</param>
        /// <param name="YAxis">The YAxis</param>
        public Thumbstick(IAxis XAxis, IAxis YAxis)
        {
            this.XAxis = XAxis;
            this.YAxis = YAxis;
            this.ReverseX = false;
            this.ReverseY = false;
            _Vector = new Vector2(XAxis.Value, YAxis.Value);
            CurrentDown = (Math.Abs(_Vector.Length()) >= 0.5);
            LastDown = CurrentDown;
            Repeated = false;
        }

        /// <summary>
        /// Create a thumbstick from wasd.
        /// </summary>
        /// <param name="Keypad">Keypad</param>
        public static Thumbstick FromKeypadWASD(Keypad Keypad)
        {
            return new Thumbstick(new FakeAxis(Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.D), Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.A)), new FakeAxis(Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.W), Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.S)));
        }

        /// <summary>
        /// Create a thumbstick from arrows
        /// </summary>
        /// <param name="Keypad">Keypad</param>
        public static Thumbstick FromKeypadArrows(Keypad Keypad)
        {
            return new Thumbstick(new FakeAxis(Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.Right), Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.Left)), new FakeAxis(Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.Up), Keypad.GetKey(Microsoft.Xna.Framework.Input.Keys.Down)));
        }

        /// <summary>
        /// Create a thumbstick from InputObjects
        /// </summary>
        /// <param name="PosX">Positive X</param>
        /// <param name="NegX">Negative X</param>
        /// <param name="PosY">Positive Y</param>
        /// <param name="NegY">Negative Y</param>
        /// <returns>The thumbstick</returns>
        public static Thumbstick FromInputObjects(IInputObject PosX, IInputObject NegX, IInputObject PosY, IInputObject NegY)
        {
            return new Thumbstick(new FakeAxis(PosX, NegX), new FakeAxis(PosY, NegY));
        }

        /// <summary>
        /// The value
        /// </summary>
        public Vector2 Vector { get { return new Vector2((this.ReverseX ? -_Vector.X : _Vector.X), (this.ReverseY ? -_Vector.Y : _Vector.Y)); } }

        /// <summary>
        /// Reverse?
        /// </summary>
        public bool ReverseX { get; set; }

        /// <summary>
        /// Reverse?
        /// </summary>
        public bool ReverseY { get; set; }

        /// <summary>
        /// Update the axis.
        /// </summary>
        public void Update(LumoComponent Game)
        {
            // Only called once per frame.
            if (_FrameID == Game.FrameID)
                return;
            _FrameID = Game.FrameID;

            this.XAxis.Update(Game);
            this.YAxis.Update(Game);

            _Vector.X = XAxis.Value;
            _Vector.Y = YAxis.Value;

            LastDown = CurrentDown;
            CurrentDown = (Math.Abs(_Vector.Length()) >= 0.5);
            Repeated = false;
            if (Game == null)
            {
                Repeated = Triggered;
                return;
            }

            if (CurrentDown)
            {
                if (!LastDown)
                {
                    Repeated = true;
                    RepeatCount = _RepeatDelay;
                }
                else
                {
                    RepeatCount -= (float)Game.GameTime.ElapsedGameTime.TotalMilliseconds;
                    if (RepeatCount <= 0)
                    {
                        Repeated = true;
                        RepeatCount = _RepeatTime;
                    }
                }
            }
        }

        /// <summary>
        /// Type of object.
        /// </summary>
        /// <returns>The type of object.</returns>
        public InputType GetInputType() { return InputType.Axis; }

        /// <summary>
        /// Return the Button.
        /// </summary>
        /// <returns>The ID.</returns>
        public long GetInputID() { return 0; }

        /// <summary>
        /// Property to check if key is pressed.
        /// </summary>
        public bool Pressed { get { return CurrentDown; } }

        /// <summary>
        /// Property to check if key is triggered.
        /// </summary>
        public bool Triggered { get { return (CurrentDown && !LastDown); } }

        /// <summary>
        /// Property to check if key is repeated.
        /// </summary>
        public bool Repeated { get; private set; }

        /// <summary>
        /// Property to check if key is released.
        /// </summary>
        public bool Released { get { return (LastDown && !CurrentDown); } }

        /// <summary>
        /// Implemented IInputObject Released.
        /// </summary>
        /// <returns>True if the key is released.</returns>
        public float RepeatDelay { get { return _RepeatDelay; } set { _RepeatDelay = value; } }

        /// <summary>
        /// Implemented IInputObject Released.
        /// </summary>
        /// <returns>True if the key is released.</returns>
        public float RepeatTime { get { return _RepeatTime; } set { _RepeatTime = value; } }
    }
}
